/*
	 
iTransmogrify!

by: Joe Maller 
	joe@joemaller.com
	
Project: http://itransmogrify.googlecode.com/


The following code will be injected into whatever page you're viewing,
automatically detecting and converting many embedded Flash links into 
clickable image links which open in the Safari or the iPhone YouTube player.

Please don't paste this code directly into a page or bookmark. Using the
bookmarklet will automatically pull the most recent stable version of
the code from the Google Code repository.


// javascript:if%20(typeof%20iTransmogrify%20==%20%27undefined%27)%20{d%20=%20document;s%20=%20d.createElement(%27script%27);s.setAttribute(%27src%27,%20%27http://itransmogrify.googlecode.com/files/ConvertYouTubeEmbedsToLinksForiPhone.js?q=%27%20+%20(new%20Date).getTime());d.getElementsByTagName(%27head%27)[0].appendChild(s);}void%200;
if (typeof iTransmogrify == 'undefined') {
    d = document;
    s = d.createElement('script');
    s.setAttribute('src', 'http://itransmogrify.googlecode.com/files/ConvertYouTubeEmbedsToLinksForiPhone.js?q=' + (new Date).getTime());
    d.getElementsByTagName('head')[0].appendChild(s);
}
void 0;
*/





// gdata is a placeholder to workaround a Google feed bug: http://code.google.com/p/gdata-issues/issues/detail?id=295

gdata = {
	io: {
		handleScriptLoaded:	function(data) {
			iTransmogrify.YTJSONhandler(data); // send raw data back to the main object. This is a workaround placeholder, treat it like one.
		}
	}
};


iTransmogrify = {
	jQueryURL: 'http://jqueryjs.googlecode.com/files/jquery-1.2.1.min.js',	// grab JQuery from Google Code
	jQueryVersion: '1.2.1', 
	appleQuickTimeLib: 'http://wdirect.apple.com/main/js/ac_quicktime.js',
	joesInfoURL: 'http://itransmogrify.googlecode.com/',
	imageBaseURL: 'http://itransmogrify.googlecode.com/svn/trunk/images/',	// grab interface images from Google Code SVN

	YTregex: /(?:youtube.com\/v\/|youtube.com\/watch\?v=)([^&]+)/, // returns YTids from http://www.youtube.com/v/TOpn32Gg88A and http://www.youtube.com/watch?v=TOpn32Gg88A urls
	mp3regex: /=((?:http|\/)[^&]*\.mp3)/,	// extracts full-path URLs ending in .mp3 from query strings used frequently in param flashvars

	// imageBaseURL: 'http://joes-mbp.local:9009/images/',	// use local images
	
	init: function() {
		if (typeof jQuery == "undefined" || jQuery.prototype.jquery < this.jQueryVersion){	// jQuery is not loaded on the page yet or is an older version
			var thisParent = this;
			var s=document.createElement('script');
			s.src=this.jQueryURL;
			s.onload = function() {     // onload handler supported by Safari and Firefox, I hate having the object name in here, but it was breaking Firebug when I tried reassigning it
			    jQuery.noConflict();
			    thisParent.getObjectAndEmbeds();
			    };
			document.getElementsByTagName('head')[0].appendChild(s);
		} else {
			this.getObjectAndEmbeds()
		}
	},
	
	getObjectAndEmbeds: function() {
		// function returns an array of objects like {type:'type', jquery object, YTid/url}
		// supported types: youtube, mp3
	
		var YouTubeItems, mp3Tags, foundObjects;
		var thisParent = this;
		foundObjects = [];
		
		// collect YouTube items:
        YouTubeItems = jQuery("embed[src*='youtube.com']"); // get standard YouTube embeds and UFO inserted Webkit bare-embeds
		YouTubeItems = YouTubeItems.add(jQuery("object[data*='youtube.com']"));	// get Mozilla UFO bare objects
		YouTubeItems.each(function() {
            foundObjects.push({
                type: 'youtube',
                jq: (jQuery(this).parent().is('object')) ? jQuery(this).parent() : jQuery(this),
                YTid: thisParent.getYTid(this)
            });
        });	
            
    	// collect mp3 items:
		mp3Tags = jQuery("param[value*='mp3']").filter(function(){return this.name.toLowerCase() =="flashvars"});
		mp3Tags = mp3Tags.add(jQuery("embed[flashvars*='mp3']"))
		mp3Tags.each(function() {
    	        var w = window.location;
    		    var mp3url = thisParent.getMP3url(this);
				foundObjects.push( {
									type: 'mp3', 
                                    jq: (jQuery(this).parent().is('object')) ? jQuery(this).parent() : jQuery(this),
									url: (mp3url.indexOf('http') == -1) ? w.protocol + '//' + w.hostname + mp3url : mp3url
									});
		});
        
		// collect dailymotion items: (coming soon)


		// send results to convertObjectsToLinks to route to appropriate functions:
		this.convertObjectsToLinks(foundObjects);
        this.cleanup(foundObjects);
	},
	
	convertObjectsToLinks: function(foundObjects) {
		var thisParent = this;
		// this expects an array of objects from getObjectEmbeds, it sends each type to the appropriate function
		jQuery(foundObjects).each(function(){
			if (this.type=='youtube') thisParent.replaceLinks(this); 
			if (this.type=='mp3') thisParent.replaceLinks(this);
			// if (item.type=='dailymotion')
		})
	},

	cleanup: function(foundObjects) {
			var thisParent = this;
			jQuery(foundObjects).each(function(){
                if (this.type == 'youtube') thisParent.getYTTitles(this.YTid);
                if (this.type == 'mp3') thisParent.getMP3titles(this.url);
			})
	},
		
	getYTTitles: function(YTid) {
		var thisParent = this;
		var gdataURL = "http://gdata.youtube.com/feeds/videos/" + YTid + "?alt=json-in-script";
		// can't use JQuery to insert these scripts because of a bug in Google's GData handling 
		// of single-item YouTube feeds, if there's a callback specified then Google spits back 
		// a bad result more info here: http://code.google.com/p/gdata-issues/issues/detail?id=295
		
		var s = document.createElement('script');
		s.src = gdataURL;
		s.setAttribute('id', 'script' + YTid); 	// for cleanup later on, also used to prevent double-inserted titles
		document.getElementsByTagName('head')[0].appendChild(s); // Gdata will callback to insertYTTitles() after loading the script
		
		// build a fake error handler
		// this will call the insertYTTitles after 2 seconds. The timer clears 
		// in the JSON handler so it will only call on bad script loads
		this['timer' + YTid ] =  setTimeout(function(){thisParent.insertYTTitles(YTid)}, 4000);	// this is our fake error handler
	},
	
	
	
	YTJSONhandler: function(data) {
		if (YTid = this.YTregex.exec(data.entry.link[1].href)) {
			this[YTid[1]] = data.entry;	// store YT JSON info under the unique ID of the movie
			clearTimeout(this['timer' + YTid[1]])	// clear the timeout (the fake an error handler)
			this.insertYTTitles(YTid[1]);
		}
	},
	
	insertYTTitles: function(YTid) {
		if (!this[YTid]) {
			// movie info failed to load, no JSON data loaded
			var YTtitle = 'Video not found';
			var YTtime = '--:--';
		} else {
			if (this[YTid] && jQuery('#script' + YTid).length) {
				// JSON data loaded and script still exists
				var YTtitle = this[YTid].title.$t
				var YTtime = this[YTid].media$group.yt$duration.seconds;
				YTtime = parseInt(YTtime/60) + ':' + ((YTtime%60 < 10) ? '0' + YTtime%60 : YTtime%60);
			}
		}

        YTtitle = YTtitle + ' &nbsp; <span style="color:#888;">' + YTtime + '</span>';
		jQuery('#script' + YTid).remove(); // remove this specific JSON script

        this.swapTitle(jQuery('#' + YTid+' .YTtitle'), YTtitle)
	},
	
	swapTitle: function(jq, title) {
	    setTimeout(function(){
	        jq.animate({textIndent:"-" + jQuery(this).width() +"px"}, 300, function() {jQuery(this).html(title)}).animate({textIndent: 0}, 500)
		}, 250);
	},
    
	nameCleaner: function(oldName) {
	    // scrubs a string to make it usable as an id/class name
	    return unescape(oldName).replace(/\W/g, "_");
	},
	
	
	getMP3titles: function(mp3url) {
        this.swapTitle(
            jQuery('#' + this.nameCleaner(mp3url.split('/').pop()) +' .YTtitle'), 
            unescape(mp3url.split('/').pop())
        )
	},
	
	
	getYTid: function(YTobject) {
		var YTid;
		if (YTid=this.YTregex.exec(YTobject.src)) return YTid[1];
		if (YTid=this.YTregex.exec(YTobject.data)) return YTid[1];
		return false;
	},
	
	getMP3url: function(mp3object) {
		var mp3url;
		if (mp3url=this.mp3regex.exec(mp3object.value)) return mp3url[1];
		if (mp3url=this.mp3regex.exec(jQuery(mp3object).attr('flashvars'))) return mp3url[1];   // for UFO inserted bare embeds
		return false;
	},
	
	
	getSizes: function(YT) {
	    // assign sizing values for YouTube rectangles
	    // sets the values into known properties of the passed YT object

        if (YT.w == "undefined" ||  YT.h == "undefined") return false;

		YT.img.w = YT.w;
		YT.img.h = YT.h;

        if (YT.type == "youtube" || YT.type == "dailymotion") {
		    YT.img.h -= YT.bar.h;
		    
    		// 0.84 is the default proportion of the YouTube player when the width is <= 400 (400x300 + 36px for the controller)
    		if (YT.w < 400 || YT.h < 336) {
    			// controller will be less than 36px tall
    			if (YT.h/YT.w < 0.84) { 
    				YT.img.w = Math.round(YT.h/0.84);
    				YT.img.h = Math.round(YT.img.w * 0.75);
    			} else {
    				YT.img.h = Math.round(YT.w * 0.75);
    			}
    			YT.bar.h = Math.round(YT.img.w * 0.84 - YT.img.w * 0.75);
			
    		} else { 
    			// width greater than 400, controller will be 36px tall
    			if (YT.h/YT.w < (YT.w * 0.75 + 36)/YT.w) { 
    				YT.img.w = Math.round(YT.img.h/0.75);
    			} else {
                    YT.img.h = Math.round(YT.img.w * 0.75);
    			}	
    		}
    		
    		// these variables simplify output positioning
    		YT.img.left = ((YT.w - YT.img.w)/2); 
            YT.img.top = Math.ceil((YT.h - YT.img.h - YT.bar.h)/2);
            YT.bar.top = YT.img.top + YT.img.h;

        } else {
            if (YT.h < 36) YT.h = YT.img.h = 36;
            if (YT.w < YT.h * 8) YT.w = YT.img.w = YT.h * 8;
            
            YT.img.left = 0;
            YT.img.top = 0;
            YT.bar.top = 0;
        }
	},

	
	replaceLinks: function(YTitem) {			
		var YT = { img: {}, bar: {} };
		YT.type = YTitem.type
		if (YT.type == "youtube") { 
		    YT.id = YTitem.YTid;
    		YT.url = 'http://www.youtube.com/watch?v=' + YT.id;
	    }
		if (YT.type == "mp3") {
		    YT.id = this.nameCleaner(YTitem.url.split('/').pop());		    
		    YT.url = YTitem.url;
		}
		YT.bar.h = 36; // default size, scales down if height is less than 36 (YT.img.w * 0.75 + 36)
		YT.w = YTitem.jq.attr('width');
		YT.h = YTitem.jq.attr('height');
            
        this.getSizes(YT);

		YT.div = '<div class="YTblock" id="' + YT.id + '" style="\
                    									 	     width: ' + YT.w +'px; \
                    										     height: ' + YT.h + 'px; \
                    										     display: inline-block;	\
                    										     position: relative; \
                    										     margin: 0;	\
                    										     padding: 0 0 0 0; \
                    										     text-align: center; \
                    										     line-height: 0;">';
														
		YT.link = '<a class="YTlink" href="' + YT.url + '" style="\
		                                                          background: transparent; \
		                                                          text-decoration: none;">';
		
		YT.button = '<div class="YTbutton" style="\
												position: absolute; \
												width: ' + YT.img.w + 'px; \
												height: ' + YT.img.h + 'px; \
												left: ' + YT.img.left + 'px; \
												top:' + YT.img.top + 'px; \
												margin: 0; \
												padding: 0; \
												background: transparent url(' + this.imageBaseURL + 'play.png) no-repeat center center; " />';
												
		YT.img.tag = '<img src="http://img.youtube.com/vi/' + YT.id + '/0.jpg" style="\
												position: absolute; \
												top: ' + YT.img.top + 'px; \
												left: ' + YT.img.left + 'px; \
												width: ' + YT.img.w + 'px; \
												height: ' + YT.img.h + 'px; \
												border:none; \
												margin: 0; \
												padding: 0;" />';
																					
		YTbottom = '<img class="YTbottom" src="' + this.imageBaseURL + 'bar.png" style="\
												position: absolute; \
												top: ' + YT.bar.top + 'px; \
												left: ' + YT.img.left + 'px; \
												height: ' + YT.bar.h + 'px; \
												width:' + YT.img.w + 'px; \
												border: none; \
												padding: 0; \
												margin: 0; \
												background: transparent;"/>';
												
		YTtitlediv = '<div class="YTtitle" style="\
												position: absolute; \
												left: ' + YT.img.left + 'px; \
												top: ' + YT.bar.top + 'px; \
												width: ' + (YT.img.w - YT.bar.h/2) + 'px; \
												padding: ' + Math.floor(YT.bar.h/4) + 'px; \
												margin: 0; \
												font: ' + (YT.bar.h * 0.5) + 'px helvetica; \
												text-align: left;  \
												line-height: ' + (YT.bar.h * 0.5) + 'px; \
												color: #ddd; \
												white-space: nowrap; \
												overflow: hidden;';
												
		if (YT.type == 'mp3') YTtitlediv += 'background: transparent url(' + this.imageBaseURL + 'music.png) no-repeat left center;\
		                                      width: ' + (YT.img.w - YT.bar.h/2 - 32) + 'px; \
		                                      padding-left: 32px;'									
		YTtitlediv += '">';
				
        if (YT.type == 'youtube')   YTtitlediv += 'Open in YouTube Viewer';
        if (YT.type == 'mp3')       YTtitlediv += 'Listen to MP3';
        
        YTtitlediv += '</div>';
												
		YTinfoLink = '<img src="' + this.imageBaseURL + 'fade.png" style="\
				                                position: absolute; \
												top: ' + YT.bar.top + 'px; \
												left: ' + (YT.img.left + YT.img.w - YT.bar.h * 2) + 'px; \
												height: ' + YT.bar.h + 'px; \
												width: ' + (YT.bar.h * 2) + 'px; \
												border: none; \
												background: transparent;" />\
		              <a class="YTinfoLink" href="' + this.joesInfoURL + '" target="_blank" style="\
												position: absolute; \
												top: ' + YT.bar.top + 'px; \
												text-decoration: none; \
												left: ' + (YT.img.left + YT.img.w - YT.bar.h) + 'px; \
												background: transparent; \
                                                text-decoration: none;"> \
				      <img src="' + this.imageBaseURL + 'info.png" style="\
												width:' + YT.bar.h + 'px; \
												border: none; \
												background: transparent; \
												max-width: none; \
												margin:0; \
												padding:0;" /></a>';


        if (YT.type == 'youtube') 
            YT.newHTML = jQuery(YT.div + YT.link + YT.img.tag + YT.button + YTbottom + YTtitlediv + "</a>" + YTinfoLink + "</div>");
        if (YT.type == 'mp3')    		
            YT.newHTML = jQuery(YT.div + YT.link + YTbottom + YTtitlediv + "</a>" + YTinfoLink + "</div>");

        YTitem.jq.replaceWith(YT.newHTML);
	}
}

iTransmogrify.init();
